﻿using HystereticBasic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace HystereticRegularization
{
    /// <summary>
    /// 计算任意曲线拐点方法
    /// </summary>
    public class RegularizedNormalCurveSOE : CureveRegularizedSOE
    {
        /// <summary>
        /// 重设正则化曲线参数
        /// </summary>
        public bool SetRegularizedBasicParam()
        {
            //初始化
            Tuple<double, RegularizedNormalCurve> cuverParamTuple;
            //双曲线正则化
            if (!this.GetRegBasic(out cuverParamTuple)) return false;
            //最优参数
            this.paramObj = cuverParamTuple.Item2;
            return true;
        }

        /// <summary>
        /// 根据峰值指向型数学模型正则化力位移曲线
        /// </summary>
        private bool GetRegBasic(out Tuple<double, RegularizedNormalCurve> paramTuple)
        {
            //字典
            var energyDict = new SortedDictionary<double, RegularizedNormalCurve>();
            //参数增量
            var deltaValue = HystereticRegParam.NormalCurveRegParamDelta;
            //遍历参数
            for (var afa = deltaValue; afa < 1; afa += deltaValue)
            {
                for (var beta = deltaValue; beta < 1; beta += deltaValue)
                {
                    //构造参数
                    var basic = new RegularizedNormalCurve(this, afa, beta);
                    //是否满足参数要求
                    if (!basic.isParamLegal()) continue;
                    //能量误差
                    var energy = basic.GetEnergyError(this.SparaseObj);
                    //判断键值是否存在
                    if (!energyDict.ContainsKey(energy)) energyDict.Add(energy, basic);
                }
            }
            //初始化
            paramTuple = Tuple.Create<double, RegularizedNormalCurve>(0, new RegularizedNormalCurve());
            //不存在合法对象
            if (energyDict.Count == 0) return false;
            //获得最优对象
            paramTuple = Tuple.Create<double, RegularizedNormalCurve>(energyDict.Keys.ToList().First(),
                 energyDict.Values.ToList().First());
            return true;
        }

        /// <summary>
        /// 获得目标力位移曲线数据
        /// </summary>
        /// <returns></returns>
        public MontForceDispObj GetTargetForceDispObj()
        {
            //初始化
            var forceDispObj = new MontForceDispObj();
            //原始数据不存在
            if (this.originalDataObj.Count == 0) return forceDispObj;
            //正则化成功
            if (this.isSuccess)
            {
                forceDispObj.AddRange(this.paramObj.GetTargetForceDispObj());
            }
            //正则化失败
            else
            {
                forceDispObj.Add(new ForceDispBasicPair(this.PointI));
                forceDispObj.Add(new ForceDispBasicPair(this.PointJ));
            }
            return forceDispObj;
        }

        /// <summary>
        /// 拐点
        /// </summary>
        /// <param name="prt"></param>
        /// <returns></returns>
        public bool GetBreakPt(out ForceDispBasicPair pt)
        {
            //初始化
            pt = new ForceDispBasicPair();
            //正则化失败
            if (!this.isSuccess) return false;
            //获得正则化点
            var obj = this.GetTargetForceDispObj();
            //存在三个点
            if (obj.Count == 3) pt = obj[1];
            //存在拐点
            return true;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void initial()
        {
            //数据点大于2
            if (this.originalDataObj.Count <= 2 || this.DeltaDisp == 0) return;
            //获得数据
            this.SparaseObj = this.originalDataObj.GetForceDispObjBySameIncreate(this.DeltaDisp, this.PointJ);
            //目标包围能量
            this.targetEnergy = this.SparaseObj.GetEnergy();
            //设定参数
            this.isSuccess = this.SetRegularizedBasicParam();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public RegularizedNormalCurveSOE()
        {
            //初始化
            this.originalDataObj = new MontForceDispObj();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="forceDispObj"></param>
        /// <param name="prtI"></param>
        /// <param name="prtJ"></param>
        public RegularizedNormalCurveSOE(MontForceDispObj forceDispObj, ForceDispBasicPair prtI, ForceDispBasicPair prtJ)
            : this()
        {
            //初始化
            this.PointJ = prtJ;
            //是否单调
            if (!forceDispObj.isMonotonous())
            {
                this.originalDataObj.Add(prtI);
                this.originalDataObj.Add(prtJ);
                return;
            }
            //遍历数据 获得区间点
            for (int i = 0; i < forceDispObj.Count; i++)
            {
                //位移
                var disp = forceDispObj[i].Disp;
                //判断是否区间
                if ((prtI.Disp - disp) * (prtJ.Disp - disp) > 0) continue;
                //增加数据
                this.originalDataObj.Add(forceDispObj[i]);
            }
            //初始化
            this.initial();
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="forceDispObj"></param>
        public RegularizedNormalCurveSOE(MontForceDispObj forceDispObj)
             : this()
        {
            //数据为空
            if (forceDispObj.Count == 0) return;
            //获得数据点离散数目
            this.regPtrNum = HystereticRegParam.NormalCurveRegPtrNum;
            //初始化
            this.PointJ = forceDispObj.Last();
            var prtI = forceDispObj.First();
            //是否单调
            if (!forceDispObj.isMonotonous())
            {
                this.originalDataObj.Add(prtI);
                this.originalDataObj.Add(this.PointJ);
                return;
            }
            //增加数据
            this.originalDataObj = new MontForceDispObj(forceDispObj);
            //初始化
            this.initial();
        }
    }
}
